local versionstring = "1.3"
local mountifulcreated = false
local invalidnames = {"hide","remove","add","smart","mounts","safeflying","options","rebuild","debug"} --Invalid panel names
local petsummoned

-- Checks if value e is in array t
local function in_array(e, t) 
 	for _,v in pairs(t) do
		if (v==e) then return true end
	end
	return false
end
local function debugmsg(msg)
	if Mountiful_Options.debugging then
		print(msg)
	end
end


function Mountiful_OnLoad()
	this:RegisterEvent("VARIABLES_LOADED")
	this:RegisterEvent("COMPANION_LEARNED");

	--Register Slash Commands
	SLASH_MOUNT1 = "/mountiful"
	SLASH_MOUNT2 = "/mount" -- A shortcut or alias
	SlashCmdList["MOUNT"] = function(arg) Mountiful_Command(arg, false); end;

	SLASH_PET1 = "/pet"
	SlashCmdList["PET"] = function(arg) Mountiful_Command(arg, true); end;

	-- Binding Variables
	BINDING_HEADER_MOUNTIFULHDR = "Mountiful Bindings"
	BINDING_NAME_MOUNTIFULBIND1 = "Smart Mounting"
	BINDING_NAME_MOUNTIFULBIND2 = "Ground"
	BINDING_NAME_MOUNTIFULBIND3 = "Flying"
	BINDING_NAME_MOUNTIFULBIND4 = "Other"
	BINDING_NAME_MOUNTIFULBIND5 = "Other2"


end
function Mountiful_OnEvent()
	if (event == "VARIABLES_LOADED") then
		Mountiful_Loaded()
	elseif (event == "COMPANION_LEARNED") then
		Mountiful_RebuildSelections()
	end
end
function Mountiful_Loaded()
	local Mountiful_Defaults = {
		["Options"] = {
			revision = 18,
			safeflying = true,
			debugging = false,
		},
		["Categories"] = {
			[1] = "Ground",
			[2] = "Flying",
			[3] = "Other",
			[4] = "Other2",
			[5] = "Pet",
		},
		["Categories_Selections"] = {
			["Pet"] = {
				isPet = true,
			},
		},
		["Mounts"] = {
			count = 0,
			extremeflyers = {},
			fastflyers = {},
			slowflyers = {},
			fastground = {},
			slowground = {},
		}
	}
	if Mountiful_Vars and Mountiful_Vars.version then
		Mountiful_Vars = nil
	end
	if not Mountiful_Vars then
		Mountiful_Vars = Mountiful_Defaults
	end

	if Mountiful_Vars.revision or Mountiful_Vars["Options"]["revision"] <  Mountiful_Defaults["Options"]["revision"] then
		if Mountiful_Vars.revision then
			Mountiful_Vars.revision = nil
			Mountiful_Vars.safeflying = nil
			Mountiful_Vars["Categories_Selections"] = {}
			for k, v in ipairs(Mountiful_Vars.panes) do
				Mountiful_Vars["Categories_Selections"][v] = Mountiful_Vars[v]
				Mountiful_Vars[v] = nil
			end
			Mountiful_Vars["Categories"] = Mountiful_Vars.panes
			Mountiful_Vars.panes = nil
		end
		for k, v in pairs(Mountiful_Defaults) do
			if not Mountiful_Vars[k] then
				Mountiful_Vars[k] = Mountiful_Defaults[k]
			end
		end
	end
	
	Mountiful_Options = Mountiful_Vars["Options"]
	Mountiful_Mounts = Mountiful_Vars["Mounts"]
	Mountiful_Categories = Mountiful_Vars["Categories"]
	Mountiful_Selections = Mountiful_Vars["Categories_Selections"]
end
function Mountiful_GetCommand(msg)
	if msg then
		local a,b,c=strfind(msg, "(%S+)") --contiguous string of non-space characters
		if a then
			return c, strsub(msg, b+2)
		else	
			return ""
		end
	end
end

function Mountiful_Command(msg, isPet) -- parse /slash commands
	local Cmd, SubCmd = Mountiful_GetCommand(msg)
	local tmpcmd, ismountcmd
		for i, panel in pairs(Mountiful_Categories) do
			tmp = strlower(panel)
			if (Cmd == tmp) then
				ismountcmd = true
				tmpcmd = panel
				break
			end
		end
		if (ismountcmd) then
			Mountiful_Mount(tmpcmd)
		elseif (Cmd == "hide") then
			Mountiful:Hide()
		elseif (Cmd == "add") then
			Mountiful_AddPanel(SubCmd, isPet)
		elseif (Cmd == "remove") then
			Mountiful_RemovePanel(SubCmd)
		elseif (Cmd == "smart") then
			if SubCmd == "pre" or SubCmd == "predefined" then
				Mountiful_SmartMount(true)
			else
				Mountiful_SmartMount()
			end
		elseif (Cmd == "rebuildselections") then
			print("Rebuilding mount selections database")
			Mountiful_RebuildSelections()
		elseif (Cmd == "debug") then
			Mountiful_Options.debugging = not Mountiful_Options.debugging
			if Mountiful_Options.debugging then
				print("Debugging on")
			else
				print("Debugging off")
			end
		elseif (Cmd == "safeflying") then
			Mountiful_Options.safeflying = not Mountiful_Options.safeflying
			if Mountiful_Options.safeflying then
				print("Safe dismounting on")
			else
				print("Safe dismounting off")
			end
		else	
			Mountiful_CreateOptions()
			Mountiful:Show()
		end
end
function Mountiful_CreateOptions()
	if mountifulcreated then return; end
	mountifulcreated = true
	
	local title = _G["Mountiful_Frame_Title"]
	title:SetText(title:GetText()..versionstring)
	
	for i, panelname in ipairs(Mountiful_Categories) do --Loop through panels stored in SV
		panel = Mountiful_CreatePanel(i, panelname, 1)
		Mountiful_CreateMountSelectors(panelname, panel)
	end
end
function Mountiful_CreatePanel(i, panelname, page)
		local parent = getglobal("Mountiful")
		local leftpane = getglobal("Mountiful_LeftPane")
		if page == 1 then
			panel = CreateFrame("Frame", panelname.."_1", parent, "RightPane_Template")
			local paneltext = getglobal(panel:GetName().."_Name")
			local button = CreateFrame("Button", panelname.."_Button", leftpane, "LeftMenuButton")
			getglobal(panelname.."_1".."_PrevPage"):Disable()
			button:SetText(panelname)
			paneltext:SetText(panelname)
			if i > 1 then
				local lastbutton = getglobal(Mountiful_Categories[i-1].."_Button")
				button:SetPoint("TOP", lastbutton, "BOTTOM", 0, 0)
				panel:Hide()
			end
		else
			local paneltextname = strsplit("_", panelname)
			paneltextname = paneltextname.." Page "..page
			panel = CreateFrame("Frame", panelname, parent, "RightPane_Template")
			local paneltext = getglobal(panel:GetName().."_Name")
			paneltext:SetText(paneltextname)
			panel:Hide()
		end
		return panel
end
local lastpane
function Mountiful_PanelSelect()
	if not lastpane then 
		 lastpane = getglobal(Mountiful_Categories[1].."_1") 
	end
	lastpane:Hide()
	local pane = string.sub(this:GetName(), -0, -8)
	pane = pane.."_1"
	pane = getglobal(pane)
	pane:Show()
	lastpane = pane
end

function Mountiful_CreateMountSelectors(panelname, parent)
	local lastmount, rowfirst, newpage
	local basepanelname = panelname
	local page = 1
	local companionType = "MOUNT"
	if (Mountiful_Selections[panelname] and Mountiful_Selections[panelname].isPet) then
		companionType = "CRITTER";
	end
	mountnum = GetNumCompanions(companionType)
	if mountnum < 25 then
		getglobal(panelname.."_1".."_NextPage"):Disable()
	end
	for i=1, mountnum do
		if mod(i, 24) == 1 and i ~= 1 then
			page = page + 1
			panelname = panelname.."_"..page
			parent = Mountiful_CreatePanel(nil, panelname, page)
			newpage = true
		end
		local _, mountname, spellID, icon, _ = GetCompanionInfo(companionType, i)
		local mount = CreateFrame("Frame", panelname.."_"..mountname, parent, "Mount")
		local button = getglobal(panelname.."_"..mountname.."_MountIcon")
		local mounttexture = getglobal(panelname.."_"..mountname.."_MountIcon_IconTexture")
		local checkbox = getglobal(panelname.."_"..mountname.."_CheckButton")
		mounttexture:SetTexture(icon)
		checkbox:SetID(i)
		
		if (Mountiful_Selections[basepanelname]) then
			if (Mountiful_Selections[basepanelname][mountname]) then
				checkbox:SetChecked(Mountiful_Selections[basepanelname][mountname]["checked"])
			else
				checkbox:SetChecked(false)
			end
		else
			checkbox:SetChecked(false)
		end

		--Set Tooltips
		button:SetScript("OnEnter", function()
				local link = GetSpellLink(spellID)
				GameTooltip:SetOwner(button, "ANCHOR_TOPRIGHT")
				GameTooltip:SetHyperlink(link)
				GameTooltip:Show()
				end
			)
		button:SetScript("OnLeave", function() GameTooltip:Hide() end)
		
		--Set Relative Positions if more then 1 mounts exists
		if not newpage then
			if (i == 1) then
				rowfirst = mount
			elseif (mod(i, 6) == 1) then
				mount:SetPoint("TOPLEFT", rowfirst, "BOTTOMLEFT", 0, 0)
				rowfirst = mount
			else
				mount:SetPoint("TOPLEFT", lastmount, "TOPRIGHT", 0, 0)
			end
		else
			newpage = false
			rowfirst = mount
		end

		lastmount = mount
	end
end

function CheckBox_OnClick()
	local thispanel
	local mountname = select(-2, strsplit("_", this:GetName()))
	local id = this:GetID()
	for i, panel in pairs(Mountiful_Categories) do
		if (strfind(this:GetName(), panel)) then
			thispanel = panel
		end
	end
	if not (Mountiful_Selections[thispanel]) then
		Mountiful_Selections[thispanel] = {}
		Mountiful_Selections[thispanel][mountname] = {}
	elseif not (Mountiful_Selections[thispanel][mountname]) then
		Mountiful_Selections[thispanel][mountname] = {}
	end

	if (this:GetChecked()) then
		debugmsg(mountname..": Checked = true; id = "..id.."; thispanel = "..thispanel.."; mountname = "..mountname)
		Mountiful_Selections[thispanel][mountname]["checked"] = true
		Mountiful_Selections[thispanel][mountname]["id"] = id
	else
		debugmsg(mountname..": Checked = false; id = "..id.."; thispanel = "..thispanel.."; mountname = "..mountname)
		Mountiful_Selections[thispanel][mountname]["checked"] = false
		Mountiful_Selections[thispanel][mountname]["id"] = id
	end
end

function Mountiful_Mount(panel)
	local temparray = {}
	if Mountiful_Selections[panel] and Mountiful_Selections[panel].isPet then
		if petsummoned then
			CallCompanion("CRITTER", petsummoned)
			petsummoned = false
		else
			if Mountiful_Selections[panel] then
				for index, value in pairs(Mountiful_Selections[panel]) do
					if index ~= "isPet" then
						local checked = Mountiful_Selections[panel][index]["checked"]
						if checked then
							debugmsg(index)
							temparray[#temparray+1] = Mountiful_Selections[panel][index]["id"]
						end
					end
				end
				if (#temparray == 0) then
					print("No pets are selected")
				else
					local num = random(1, #temparray)
					CallCompanion("CRITTER", temparray[num])
					petsummoned = temparray[num]
				end
			else
				print("No pets are selected")
			end
		end
	elseif IsMounted() then
		if IsFlying() and Mountiful_Options.safeflying then
		else
			Dismount()
		end
	else
		if Mountiful_Selections[panel] then
			for index, value in pairs(Mountiful_Selections[panel]) do
				if (index ~= "isPet" and  Mountiful_Selections[panel][index]["checked"] == true) then
					temparray[#temparray+1] = Mountiful_Selections[panel][index]["id"]
				end
			end
			if (#temparray == 0) then
				print("No mounts are selected")
			else
				local num = random(1, #temparray)
				if (Mountiful_Selections[panel].isPet) then
					CallCompanion("CRITTER", temparray[num])
				else
					CallCompanion("MOUNT", temparray[num])
				end
			end
		else
			print("No mounts are selected")
		end
	end
end

function Mountiful_AddPanel(newpanel, isPet)
	local exists = false
	if newpanel == nil or newpanel == "" then
		if isPet == true then
			print("Usage: /pet add <panelname>")
		else
			print("Usage: /mount add <panelname>")
		end
	else
		newpanellower = strlower(newpanel)
		if in_array(newpanellower,invalidnames) then
			print(newpanel.." cannot be used as a Category name")
		else
			for index, value in pairs(Mountiful_Categories) do
				if newpanellower == strlower(value) then
					exists = true
				end
			end
			if exists then
				print("Cannot add panel \""..newpanel.."\", it already exists")
			else
				Mountiful_Categories[#Mountiful_Categories+1] = newpanel
				panel = Mountiful_CreatePanel(#Mountiful_Categories, newpanel, 1)
				if (not Mountiful_Selections[newpanel]) then
					Mountiful_Selections[newpanel] = { };
				end
				Mountiful_Selections[newpanel].isPet = isPet
				Mountiful_CreateMountSelectors(newpanel, panel)
			end
		end

	end
end
function Mountiful_RemovePanel(panel) --remove a panel
	removed = false
	if panel == nil then
		print("Usage: /mount remove <panelname>")
	elseif panel == "Flying" or panel == "Ground" then
		print("Cannot remove that panel")
	else
		for index, value in pairs(Mountiful_Categories) do
			if strlower(value) == strlower(panel) then
				Mountiful_Categories[index] = nil
				local uipanel = getglobal(value.."_1")
				if uipanel then
					uipanel:Hide()
				end
				if lastpanel and strfind(strlower(lastpanel:GetName()), value) then
					lastpanel:Hide()
				end
				local button = getglobal(value.."_Button")
				if button then
					button:Hide()
				end
				if (Mountiful_Selections[value]) then
					Mountiful_Selections[value] = nil
				end
				print(value.." was removed")
				removed = true
				--Gets rid of nils in the panes array
				local temp = {}
				for i,v in pairs(Mountiful_Categories) do
					temp[#temp+1] = v
				end
				Mountiful_Categories = temp
				break
			end
		end
		if removed == false then
			message (panel.." was not removed")
		end
	end
end

function Mountiful_SmartMount(predefined) --smart mounting function
	local mountnum = GetNumCompanions("MOUNT")
	local flyable
	local zoneName = GetZoneText()
	local subZone = GetSubZoneText()
	local ridingSkill = GetRidingSkill()
	local level = UnitLevel("player")
	local tmpnum
	local coldweatherflying, _ = IsUsableSpell("Cold Weather Flying")
	
	for i, v in pairs(zoneFlyLevel) do --check if the zone can be flown in
		if i == zoneName then
			if zoneFlyLevel[i] == 70 and level > 70 then
				flyable = true
			elseif (level >= zoneFlyLevel[i]) and coldweatherflying then
				flyable = true
			else
				flyable = false
			end
		end
	end
	if subZone == "Krasus' Landing" and coldweatherflying then
		flyable = true
	end
	if predefined then
		if flyable then
			Mountiful_Mount("Flying")
		else
			Mountiful_Mount("Ground")
		end
		return
	end
	if mountnum ~= Mountiful_Mounts.count then --if the number of mounts known is larger then the number stored rebuild the table
		--empty the tables
		Mountiful_Mounts.fastflyers = {}
		Mountiful_Mounts.slowflyers = {}
		Mountiful_Mounts.fastground = {}
		Mountiful_Mounts.slowground = {}

		for i=1, mountnum do
			local _, mountname, spellID, icon, _ = GetCompanionInfo("MOUNT", i)
			local link = GetSpellLink(spellID)
			CreateFrame("GameTooltip", "MountifulTooltip", UIParent, "GameTooltipTemplate")
			GameTooltip_SetDefaultAnchor(MountifulTooltip, UIParent)
			MountifulTooltip:SetHyperlink(link)
			local text = _G["MountifulTooltipTextLeft"..3]:GetText()
			MountifulTooltip:Hide()
			if strfind (text, "changes") then
				Mountiful_Mounts.fastflyers[#Mountiful_Mounts.fastflyers+1] = i
				Mountiful_Mounts.slowflyers[#Mountiful_Mounts.slowflyers+1] = i
				Mountiful_Mounts.fastground[#Mountiful_Mounts.fastground+1] = i
				Mountiful_Mounts.slowground[#Mountiful_Mounts.slowground+1] = i
			elseif strfind(text, "Outland") then
				if ridingSkill >= 300 and strfind(text, "extremely") then
					Mountiful_Mounts.extremeflyers[#Mountiful_Mounts.extremeflyers+1] = i
				elseif ridingSkill >= 300 and strfind(text, "very")then
					Mountiful_Mounts.fastflyers[#Mountiful_Mounts.fastflyers+1] = i
				else
					Mountiful_Mounts.slowflyers[#Mountiful_Mounts.slowflyers+1] = i
				end
			elseif not strfind(text, "Outland") then
				if ridingSkill >= 150 and strfind(text, "very")then
					Mountiful_Mounts.fastground[#Mountiful_Mounts.fastground+1] = i
				else
					Mountiful_Mounts.slowground[#Mountiful_Mounts.slowground+1] = i
				end
			end

		end
		Mountiful_Mounts.count = mountnum
	end
	if IsMounted() then
		if IsFlying() and Mountiful_Options.safeflying then --if user is flying and safemounting is on do nothing, else dismount
		else
			Dismount()
		end
	else
		if flyable and #Mountiful_Mounts.extremeflyers > 0 then
			tmpnum = random(1, #Mountiful_Mounts.extremeflyers)
			CallCompanion("MOUNT", Mountiful_Mounts.extremeflyers[tmpnum])
		elseif flyable and #Mountiful_Mounts.fastflyers > 0 then
			tmpnum = random(1, #Mountiful_Mounts.fastflyers)
			CallCompanion("MOUNT", Mountiful_Mounts.fastflyers[tmpnum])
		elseif flyable and #Mountiful_Mounts.slowflyers > 0 then
			tmpnum = random(1, #Mountiful_Mounts.slowflyers)
			CallCompanion("MOUNT", Mountiful_Mounts.slowflyers[tmpnum])
		elseif #Mountiful_Mounts.fastground > 0 then
			tmpnum = random(1, #Mountiful_Mounts.fastground)
			CallCompanion("MOUNT", Mountiful_Mounts.fastground[tmpnum])
		elseif #Mountiful_Mounts.slowground > 0 then
			tmpnum = random(1, #Mountiful_Mounts.slowground)
			CallCompanion("MOUNT",Mountiful_Mounts.slowground[tmpnum])
		else
			print("No mounts available")
		end
	end
end
function GetRidingSkill() --retrive and return players riding skill
	for skillIndex = 1, GetNumSkillLines() do
		skillName, _, _, skillRank, _, _, _, _, _, _, _, _, _ = GetSkillLineInfo(skillIndex)
		if skillName == "Riding" then
			return skillRank
		end
	end
end

--Goto next page of mounts/pets
function Mountiful_NextPage()
	local paneName, pageNum = strsplit("_", this:GetName())
	local currentPage = _G[paneName.."_"..pageNum]
	local pageNum = tonumber(pageNum)
	local nextPage = _G[paneName.."_"..(pageNum+1)]
	if nextPage then --check if there is a 2nd page
		currentPage:Hide()
		nextPage:Show()
		if not _G[paneName.."_"..(pageNum+2)] then --if there is no page after the one we are going to disable its next button
			_G[paneName.."_"..(pageNum+1).."_NextPage"]:Disable()
		end
	end
	lastpane = nextPage
end

--Goto previous page of mounts/pets
function Mountiful_PrevPage()
	local paneName, pageNum = strsplit("_", this:GetName())
	local currentPage = _G[paneName.."_"..pageNum]
	local pageNum = tonumber(pageNum)
	if pageNum > 1 then
		local nextPage = _G[paneName.."_"..(pageNum-1)]
		currentPage:Hide()
		nextPage:Show()
	end
	lastpane = nextPage
end

function Mountiful_RebuildSelections()
	local mountnum = GetNumCompanions("MOUNT")
	local petnum = GetNumCompanions("CRITTER")
	local num, companiontype

	for k, _ in pairs(Mountiful_Selections) do
		debugmsg("k = "..k)
		if Mountiful_Selections[k].isPet then num = petnum; companiontype = "CRITTER"
		else num = mountnum; companiontype = "MOUNT" end
		for i=1, num do
			local _, name, spellID, icon, _ = GetCompanionInfo(companiontype, i)
			for k2, _ in pairs(Mountiful_Selections[k]) do
				if k2 == name then
					Mountiful_Selections[k][k2]["id"] = i
				end
			end
		end
	end
end